/*! \file Dumper.h
    \brief Une interface permettant de manipuler un dumper templaté par 
    la grandeur que l'on souhaite instrumenter.
*/

#ifndef __Dumper__H
#define __Dumper__H



#include <stdlib.h>
#include <list>
#include <fstream>
#include <algorithm>
#include <sstream>
#include <iostream>

using namespace std;


#define ESPACE " "


/**
 *\brief interface permettant de manipuler plusieurs dumpers, permet de ne pas avoir 
 * a toucher la bibliotheque d'interception.
 *\class IDumper interface permettant de manipuler des dumpers, afin de faire de 
 * substituion d'objets.
 */
class IDumper
{
 public:
  /**
   *\brief ecrit dans un fichier le header.
   *\Par exemple heure minutes secondes.
   */
  virtual void printHeader()=0;
  
  /**
   *\brief ajoute dans l'objet la colonne titre.
   */
  virtual void insertTitre(const string &titre)=0;
  
  /**
   *\brief l'appel a cette fonction permet de lire une ligne
   * et de la dumper dans le fichier de sortie.
   */
  virtual void readAndDump()=0;
  
  /**
   *\brief force l'appel de readAndDump
   *@see readAndDump()
   */
  virtual void forceDump()=0;
  
  /**
   *\brief ne fait rien
   */
  virtual ~IDumper(){};
  
  /**
   *\brief affiche à l'ecran la mesure mémoire
   */
  virtual void printMeasure()=0;
  
 protected:
  
  /**
   *\brief methode qui doit etre implementee pour 
   *pour extraire l'information a dumper.
   */
  virtual void readLine()=0;
};





/**
 *\brief classe generique qui permet d'instancier de dumpers.
 *\class Dumper qui implemente l'interface IDumper.
 */
template <typename T> class Dumper:public virtual IDumper
{
  
 protected: 
  /**
   *\brief represente le temps en terme d'evenements d'allocation
   *Indique la valeur du compteur de dump.
   */
  int temps;
  
 private: 
  /**
   *Nombre de lignes stockees en memoire avant d'etre ecrites
   *sur disque.
   */
  int tailleCache;
  


  
  /**
   *\brief compte le nombre de lignes dumpees.
   */
  int compteurLignes;
  
  
  
  /**
   *\brief Fichier de sortie.
   */
  ofstream out;
  
  
  
  /**
   *\brief Liste des attributs de la grandeur instrumentée
   */
  list<string> titres;
  
  
  /**
   *\brief Ecrit un titre dans le fichier.
   *Titre de la colonne dans un format classique.
   */
  virtual void printTitre(const string &titre)
    {
     out << titre << ESPACE;
    }
  
  
  /**
   *\brief Ecrit une ligne dans le fichier.
   */
  inline void printLine(string &line)
    {
      out << line << ESPACE <<endl;
    }
  
 public:
  
  /**
   *\brief Ajouter la colonne titre de la grandeur a instrumenter.
   */
  
  void insertTitre(const string &titre)
  {
    this->titres.push_back(titre);
    cout <<"Insertion du header de la colonne: "<<titre<<endl;
  }
  
  virtual void printMeasure()
  {
    
  }
#define CST_FILE_OUT "example.txt"
  /**
   *\brief Constructeur par default.
   */
  Dumper(const char* path_out):IDumper()
   {
     out.open (path_out,ios::trunc);
     cout << "Instanciation du dumper."<<endl;
     this->temps=0;
     this->tailleCache=100;
     this->compteurLignes=0;
   }
 
 
  /**
   *Destructeur, permet de fermer le fichier.
   */
  virtual ~Dumper()
    {
      cout << "Finalisation de la séance de dump."<<endl;
      out.close();
    }
  

#define CST_TEMPS "Temps"
  /**
   *Ecrite le header dans le fichier.
   */
   virtual void printHeader()
    {
      out << CST_TEMPS << ESPACE;
      
      for (list<string>::iterator str=titres.begin(); str!=titres.end(); str++){
	  out << (*str) << ESPACE;
	}
	
      out << endl;
    }
  

  
  /**
   *\brief Lire une ligne et ecrire une ligne.
   */
  virtual void readAndDump()
    {
      temps++;
      this->readLine();
      this->DumpLine();
    }
  

  /**
   *Le dump se faisant par periode, il peut etre nencessaire
   *de forcer le dump losrque la duree de l'instrumentation 
   *n'atteint pas la valeur de la periode. C'est ce que fait cette
   *fonction.
   *@see printLine()
   */
  virtual void forceDump()
    {
      cout << "Forcing a dump" << endl;
      for (
	   list<string>::iterator str=lines.begin(); 
	   str!=lines.end(); 
	   str++){printLine(*str); }
    }  

  
  
  
  /**
   * Dump le cache dans le fichier.
   * @see forceDump()
   */
  inline void DumpLine()
    {
      
      if(compteurLignes % tailleCache == 0)
	{
	  
	  this->forceDump();
	  lines.clear();
	}
      return ;
    }
  
  
  
 public:
  
  /**
   *\brief stocke les informations extraites par les sondes.
   *Instance representant les valeurs des grandeurs instrumentees.
   */
  T instance;
  
  
  /**
   *Pour chaque grandeur a instrumenter 
   *l'utilisateur se doit d'implementer
   *cette methode.
   *C'est celle ci qui extrait la valeur
   *de la grandeur
   */
  virtual void readLine()=0;
  
 protected:
  /**
   *Liste stockant les lignes 
   *de sortie
   */
  list<string> lines;
  
};


#endif
